<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <div id="app">
    <h1 v-html="salary"></h1>
    <input type="text" v-model="salary">
    <p v-html="salary"></p>
    <p v-html="salary"></p>
  </div>
  <script>
    function EventBus(){
      this.guanjia = {
        // a: [],
        // b: []
      }
    }

    // 添加观察者 fn, 它观察eventName事件
    EventBus.prototype.$on = function (eventName, fn) {
      // 如果在事件中心已经注册过
      if (this.guanjia[eventName]) {
        this.guanjia[eventName].push(fn)
      } else {
        this.guanjia[eventName] = [ fn ]
      }
    }
    // 发布事件，执行相应的观察者函数
    EventBus.prototype.$emit = function (eventName) {
      if (this.guanjia[eventName]) {
        this.guanjia[eventName].forEach(fn => {
          fn()
        })
      }
    }
  </script>

  <script type="text/javascript">
      // 创建实例
      let eventCenter = new EventBus()

      var data = {
        salary:15000
      }
      // 目标: 在页面上显示初始数据

      function MVVM (options) {
        // 用解构赋值，取出配置项中内容
        let {el, data} = options
        console.log(data)
        
        // 对data中所有的可枚举属性进行循环
        // let：块级作用域，暂时性死区
        for(let key in data) {
          console.log(key)
          // 在构造器内部，this就会指向当前实例对象
          Object.defineProperty(this, key, {
            get () {
              console.log('get', key)
              return data[key]
            },
            // 在vm.salary= 10时，会自动执行set方法，并把新值10传入，给val。
            // 比较是否需要更新数据
            //   不相等，才保存新值
            set ( val ) {
              if (val !== data[key]) {
                // 1. 保存新值
                data[key] = val
                // 2. eventCenter发布事件
                eventCenter.$emit(key)
              }
            }
          })
        }

        
        // 循环el下的所有的子节点
        // 如果某个节点上有v-html, v-model则需要特殊处理
        // 1. 取出所有的子节点
        let rootDom =document.querySelector(el)
        // console.dir(Array.isArray(rootDom.children))
        // console.dir(rootDom.children)
        // rootDom.children 表示所有的子结点,它是一个伪数组，要用循环，还要转一下。
        Array.from(rootDom.children).forEach(node => {
          // console.log(node)
          // 对每一个节点，分析是否有 v-html, v-model属性？
          console.log( node.hasAttribute('v-html'))
          if (node.hasAttribute('v-html')) {
            // 1. 处理v-html指令： 把数据显示出来
            //以：  <h2 v-html="salary"></h2> 为例
            // (1) 把属性值取出来。把salary取出来
            let attrVal = node.getAttribute('v-html')
            console.log(attrVal) // attrVal : salary
            // (2) 找出对应的data中的salary的属性值15000
            console.log(this[attrVal])
            // (3) 15000 放入当前的node中
            node.innerHTML = this[attrVal]

            // 2. 数据变化，更新内容。
            // 当 salary 值时，视图也要跟着变
            // 添加观察者
            eventCenter.$on(attrVal, () => {
              // 重新更新v-html
              // console.log('检测到了',attrVal,'事件发生，需要更新' )
              node.innerHTML = this[attrVal]
            })
          }
          if (node.hasAttribute('v-model')) {
            // 1. 处理v-model指令： 把数据显示出来
            let attrVal = node.getAttribute('v-model')
            node.value = this[attrVal]

            // 2. 数据变化，更新内容。
            // 当 salary 值时，视图也要跟着变
            eventCenter.$on(attrVal, () => {
              // 重新更新v-html
              // console.log('检测到了',attrVal,'事件发生，需要更新' )
              node.value = this[attrVal]
            })
          }
        });
      }
      var vm = new MVVM({
          el:"#app",
          data
      })
      // console.log( vm.salary )
  </script>
</body>
</html>